/*********************************************************************************************************
*	Projeto Final: SCC-0143 - Programação Concorrente						
*	Professor: Julio Cezar Estrella
*	Integrantes: Cesar Augusto Sales Gomes
*		     Matheus Salgado Boscariol
*	             Robson Pereira ALeixo
*
*	Gerador de Palavras:
*		Gerar palavras com tamanhos até 5 caracteres e verificar se elas estão em um arquivo    		
*
**********************************************************************************************************/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include "mpi.h"
#include"loadArchive.h"
#include"generateAndSurch.h"


/*
	Objetivo: gerar uma palavra e verifica se a mesma encontra-se na estrutura
	parametro palavras: vetor com a palavras que devem ser encontradas
	parametro finoutWord: retorna a palavra encontrada
	parametro tamanho: tamanho do vetor de palavras 
*/
    
char geraletra(){ /*função que gera letras de 'a' a 'z' */

    char letra, letra1, letra2;
   
   letra1 = rand()%14;
   
   letra2 = rand()%13;
   
   letra = letra1 + letra2 + 97;
return letra;
}



int gerapalavra(char **palavras, char *findoutWord, int tamanho, char **palavrasEncontradas, int conPE){

    int achei = 0;
    int numLetras = 0;
    char *palavraGerada;
    int exist;
    int inicio, fim;
    int i;
    int posicaPalavra; /*seleciona uma palavra ddas tres*/
    int geraProxLetra;
    int palavraExiste = 0;
    palavraGerada = (char*)calloc(10,sizeof(char));
    
    posicaPalavra = -1;

    palavraGerada[numLetras] = geraletra();
    exist = existWord(palavraGerada, palavras, 0, tamanho);
    /*printf("exist:%d e tamanho:%d\n",exist, tamanho);*/
    if(exist == -1){
        return 0;
        /*printf("achei a palavra %s\n",palavraGerada);*/
    }else
    {
        if(exist == 0){
            inicio = exist;
            fim = 1;
        }else{
            if(exist == tamanho){
                inicio = tamanho-2;
                fim = tamanho-1;
            }else{
                inicio = exist-1;
                fim = exist+1;
            }
        }
        /*busca o vetor que começa com a letra que eu gerei*/
        /*printf("inicio:%d fim:%d\n",inicio, fim);*/
        for(i = inicio ; i <=fim ; i++){
            if(strlen(palavras[i]) <= 5){
                if(palavras[i][0] == palavraGerada[0]){
                    posicaPalavra = i;
                    i = fim+1;
                }
            }
        }
        
        geraProxLetra = 0;
        numLetras = 1;
        if(posicaPalavra >= 0){
            /*printf("posicaPalavra: %d....palavra candidata: %s\n", posicaPalavra, palavras[posicaPalavra]);*/
            /*printf("posicaPalavra: %d\n", posicaPalavra);*/
            palavraExiste = 0;
            palavraExiste = existWord(palavras[posicaPalavra], palavrasEncontradas, 0, conPE);
            
           
            if(palavraExiste >= 0){
                printf("palavra escolhida: %s\n",palavras[posicaPalavra]);
                while(achei == 0){
                    /*printf("to procurando...\n");*/
                    palavraGerada[numLetras] = geraletra();
                    printf("numLetras: %d\n",numLetras);
                    printf("[%s]comparando com: %s\n",palavraGerada,palavras[posicaPalavra]);
                    if(numLetras == 4){
                        printf("comparando %c com %c\n",palavras[posicaPalavra][numLetras-1], palavraGerada[numLetras-1]);
                       if((palavras[posicaPalavra][numLetras-4] == palavraGerada[numLetras-4])&&(palavras[posicaPalavra][numLetras-3] == palavraGerada[numLetras-3])&&(palavras[posicaPalavra][numLetras-2] == palavraGerada[numLetras-2])&&(palavras[posicaPalavra][numLetras-1] == palavraGerada[numLetras-1])&&(palavras[posicaPalavra][numLetras] == palavraGerada[numLetras])){
                            if(strlen(palavras[posicaPalavra]) == numLetras+1){
                                strcpy(findoutWord,palavraGerada);
                                /*printf("achei a palavra %s\n",palavraGerada);*/
                                achei = 1;
                                numLetras = 0;
                                return 1;
                            }else{
                                numLetras++;
                            }
                        }
                    }
                    if(numLetras == 3){
                        printf("comparando %c com %c\n",palavras[posicaPalavra][numLetras-1], palavraGerada[numLetras-1]);
                       if((palavras[posicaPalavra][numLetras-3] == palavraGerada[numLetras-3])&&(palavras[posicaPalavra][numLetras-2] == palavraGerada[numLetras-2])&&(palavras[posicaPalavra][numLetras-1] == palavraGerada[numLetras-1])&&(palavras[posicaPalavra][numLetras] == palavraGerada[numLetras])){
                            if(strlen(palavras[posicaPalavra]) == numLetras+1){
                                strcpy(findoutWord,palavraGerada);
                                achei = 1;
                                numLetras = 0;
                                return 1;
                            }else{
                                numLetras++;
                            }
                        }
                    }
                    if(numLetras == 2){
                        printf("comparando %c com %c\n",palavras[posicaPalavra][numLetras-1], palavraGerada[numLetras-1]);
                        if((palavras[posicaPalavra][numLetras-2] == palavraGerada[numLetras-2])&&(palavras[posicaPalavra][numLetras-1] == palavraGerada[numLetras-1])&&(palavras[posicaPalavra][numLetras] == palavraGerada[numLetras])){
                            if(strlen(palavras[posicaPalavra]) == numLetras+1){
                                strcpy(findoutWord,palavraGerada);
                                achei = 1;
                                numLetras = 0;
                                return 1;
                            }else{  
                                numLetras++;
                            }
                        }
                    }
                    if(numLetras == 1){
                    
                       printf("comparando %s com %c%c\n",palavras[posicaPalavra], palavraGerada[numLetras-1],palavraGerada[numLetras]);

                        if((palavras[posicaPalavra][numLetras-1] == palavraGerada[numLetras-1])&&(palavras[posicaPalavra][numLetras] == palavraGerada[numLetras])){
                            if(strlen(palavras[posicaPalavra]) == numLetras+1){
                                strcpy(findoutWord,palavraGerada);
                                achei = 1;
                                numLetras = 0;
                                return 1;
                            }else{
                                numLetras++;
                            }
                        }
                    }
                }    
            }
        }else{
            return 0;
        }
    }
}


/*
    Aloca as estrutura que armeza palavras geradas, achadas da na estrutura WFF
    parametro W: estrutura que irá armazenar as palavras geradas até cinco
*/
void alocarWG(WordGenerate *W){

	int i;

	W->tam1 = (char*) calloc(tamArrayHead, sizeof(char));
	W->tam2 = (char**) calloc(tamArrayHead, sizeof(char*));
	W->tam3 = (char**) calloc(tamArrayHead, sizeof(char*));
	W->tam4 = (char**) calloc(tamArrayHead, sizeof(char*));
	W->tam5 = (char**) calloc(tamArrayHead, sizeof(char*));

	for(i=0; i < tamArrayHead; i++){
        
        W->tam2[i] = (char*) calloc(2,sizeof(char));
		W->tam3[i] = (char*) calloc(3,sizeof(char));
		W->tam4[i] = (char*) calloc(4,sizeof(char));
		W->tam5[i] = (char*) calloc(5,sizeof(char));
	}

    
    W->qtdadePorTam = (int*)calloc(5,sizeof(int));

    W->totalWord = 0;

}
/*
    Objetivo: Essa função vai encontrar somente todas as palavras de tamanho ate cinco, as palavras maiores serão tratadas posteriormente.
    parametro WFF: estrura onde estão armazenadas as palavras do arquivo.
    parametro WG: estrutura onde estão armazenas as palavras geradas.
    
*/
void findWordUntilFive(WordGenerate *WG, WordFromFile *WFF, int ini, int fim){

    int wordFindsPorVetor = 0;
    int countVetorHead = ini; /*contador para posição dos vetores da head*/
    int i;
    int conPE = 0, posicao;
    int valida;
    char **palavrasEncontradas;

    palavrasEncontradas = (char**) malloc(50000*sizeof(char*));
    for(i=0; i < tamArrayHead; i++)
        palavrasEncontradas[i] = (char*) malloc(5*sizeof(char));

    char *wordRecv;
    wordRecv = (char *)calloc(5,sizeof(char));
    /*percorre os 100 vetores*/
    countVetorHead = 0;
    conPE = 0;
    while(countVetorHead <= fim){
        conPE = 0;/*percorre ate encontrar todas as palavras menores que cinco daquele vetor*/
        printf("procurando no vetor[%d]...com tamanho %d e %d palavras menores que cinco\n",countVetorHead,WFF->size[countVetorHead], WFF->numPorVetorAteCinco[countVetorHead]);
        while(wordFindsPorVetor < 5){

            wordRecv = (char *)calloc(5,sizeof(char));
            valida = gerapalavra(WFF->text[countVetorHead],wordRecv, WFF->size[countVetorHead], palavrasEncontradas, conPE);
            
            if(valida == 1){
                posicao = existWord(wordRecv, palavrasEncontradas, 0, conPE);                       
                insertWord(wordRecv, palavrasEncontradas, posicao, conPE);
                conPE++;
                printf("palavra encontrada %s\n", wordRecv);
                
		/*Armazena no vetor de palavras de tamanho 1*/
                if(strlen(wordRecv) == 1){

                       WG->tam1[WG->qtdadePorTam[1]] = wordRecv[0];
                       WG->qtdadePorTam[1]++;
                       WG->totalWord++;
                       wordFindsPorVetor++;
                }
		/*Armazena no vetor de palavras de tamanho 2*/
                if(strlen(wordRecv) == 2){

                       strcpy(WG->tam2[WG->qtdadePorTam[2]], wordRecv);
                       WG->qtdadePorTam[2]++;
                       WG->totalWord++;
                       wordFindsPorVetor++;
                }
		/*Armazena no vetor de palavras de tamanho 3*/
                if(strlen(wordRecv) == 3){

                       strcpy(WG->tam3[WG->qtdadePorTam[3]], wordRecv);
                       WG->qtdadePorTam[3]++;
                       WG->totalWord++;
                       wordFindsPorVetor++;
                }
		/*Armazena no vetor de palavras de tamanho 4*/
                if(strlen(wordRecv) == 4){

                       strcpy(WG->tam4[WG->qtdadePorTam[4]], wordRecv);
                       WG->qtdadePorTam[4]++;
                       WG->totalWord++;
                       wordFindsPorVetor++;
                }
		/*Armazena no vetor de palavras de tamanho 5*/
                if(strlen(wordRecv) == 5){
                       strcpy(WG->tam5[WG->qtdadePorTam[5]], wordRecv);
                       WG->qtdadePorTam[5]++;
                       WG->totalWord++;
                       wordFindsPorVetor++;
                }
            }
        }
        free(wordRecv);
        countVetorHead++;
    }
    findAllWords(WG,WFF);   /*acharPalavraTotal();*/
}
/*
    Objetivo: Concatenar as palavras do vetor principal e secundario e procurar a palavra em WFF
    parametro vetorPrincipal: vetor base que sera concatenado com todos os outros
    parametro vetorSecundario: vetor que sera concatenado com o principal
    parametro tamVetorPrincipal: tamanho do vetor principal
    parametro tamVetorSecundario: tamanho do vetor secundario
    parametro WFF: estrutura com as palavras do arquivo 
*/
int concatenarVetXVetY(char **vetorPrincipal, char **vetorSecundario, int tamVetorPrincipal, int tamVetorSecundario, WordFromFile *WFF){

    int i = 0; /*contador para o numero de palavras do vetor principal*/
    int j = 0; /*contador para o número de palavras do vetor secundario*/
    int count = 0; /*conta o número de palavras encontradas*/
    int pos = 0; /*conta o numero de vetores do WFF analisados*/
    int ansiWord = 0;
    
    /*calcula a posição em que ele será armazenado*/
    pos = (int)ansiWord%tamArrayHead;    
    
        /*loop para analise da porcentagem das palavras encontras por vetor*/
        while(((count/WFF->size[j])*100 <= porcentagem) || (i == tamVetorPrincipal-1)){
            for(i = 0 ; i < tamVetorPrincipal ; i++){
                ansiWord = valorAsciiWord(vetorPrincipal[i]);
                pos = (int)ansiWord%tamArrayHead;
                if(existWord(vetorPrincipal[i], WFF->text[pos],0,WFF->size[pos]) == -1){
                    strcat(vetorPrincipal[i], vetorSecundario[j]);
                    if(existWord(vetorPrincipal[i], WFF->text[pos],0,WFF->size[j]) == -1)
                        count++;
                }
            }        
        }
        
    return count;
}
/*  
    Objetivo: Concatenar os vetores com o vetor principal
    parametro WFF: estrura onde estão armazenadas as palavras do arquivo
    parametro WG: estrutura onde estão armazenas as palavras geradas
    parametro vetorPrincipal: vetor que será concatenado com todos os vetores da estrura 
    parametro tamVetorPrincipal: tamanho do vetor principal
    
*/
void concatenar(WordFromFile *WFF, WordGenerate *WG, char **vetorPrincipal, int tamVetorPrincipal){

        int numFindWord = 0;

        numFindWord += concatenarVetXVetY(vetorPrincipal, WG->tam2, tamVetorPrincipal, WG->qtdadePorTam[2],WFF);
        numFindWord += concatenarVetXVetY(vetorPrincipal, WG->tam3, tamVetorPrincipal, WG->qtdadePorTam[3],WFF);
        numFindWord += concatenarVetXVetY(vetorPrincipal, WG->tam4, tamVetorPrincipal, WG->qtdadePorTam[4],WFF);
        numFindWord += concatenarVetXVetY(vetorPrincipal, WG->tam5, tamVetorPrincipal, WG->qtdadePorTam[5],WFF);

        MPI_Send(&numFindWord,1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
/*  
    parametro WFF: estrura onde estão armazenadas as palavras do arquivo
    parametro WG: estrutura onde estão armazenas as palavras geradas
*/
/*Função para variar os vetores tamX Primarios*/
void findAllWords(WordGenerate *WG, WordFromFile *WFF){

    /*para o caso de tam2 ser o vetor principal*/
    concatenar(WFF,WG,WG->tam2, WG->qtdadePorTam[2]);
    concatenar(WFF,WG,WG->tam2, WG->qtdadePorTam[3]);
    concatenar(WFF,WG,WG->tam2, WG->qtdadePorTam[4]);
    concatenar(WFF,WG,WG->tam2, WG->qtdadePorTam[5]);

    /*para o caso de tam3 ser o vetor principal*/
    concatenar(WFF,WG,WG->tam3, WG->qtdadePorTam[2]);
    concatenar(WFF,WG,WG->tam3, WG->qtdadePorTam[3]);
    concatenar(WFF,WG,WG->tam3, WG->qtdadePorTam[4]);
    concatenar(WFF,WG,WG->tam3, WG->qtdadePorTam[5]);

    /*para o caso de tam4 ser o vetor principal*/
    concatenar(WFF,WG,WG->tam4, WG->qtdadePorTam[2]);
    concatenar(WFF,WG,WG->tam4, WG->qtdadePorTam[3]);
    concatenar(WFF,WG,WG->tam4, WG->qtdadePorTam[4]);
    concatenar(WFF,WG,WG->tam4, WG->qtdadePorTam[5]);

    /*para o caso de tam5 ser o vetor principal*/
    concatenar(WFF,WG,WG->tam5, WG->qtdadePorTam[2]);
    concatenar(WFF,WG,WG->tam5, WG->qtdadePorTam[3]);
    concatenar(WFF,WG,WG->tam5, WG->qtdadePorTam[4]);
    concatenar(WFF,WG,WG->tam5, WG->qtdadePorTam[5]);
}
/*
 	Objetivo: criar um arquivo com as palavras encontradas até tamanho cinco
*/
void imprimeWG(WordGenerate *WG){

    FILE *worGe;
    worGe = fopen("worGe.txt","w+");

    int i;

    for(i=0 ; i < WG->qtdadePorTam[1]; i++){
        fprintf(worGe,"linha[1]:\n");
        fprintf(worGe,"%c |",WG->tam1[i]);
    }
    fprintf(worGe,"\n");
    for(i=0 ; i < WG->qtdadePorTam[2]; i++){
        fprintf(worGe,"linha[2]:\n");
        fprintf(worGe,"%s |",WG->tam2[i]);
    }
    fprintf(worGe,"\n");
    for(i=0 ; i < WG->qtdadePorTam[3]; i++){
        fprintf(worGe,"linha[3]:\n");
        fprintf(worGe,"%s |",WG->tam3[i]);
    }
    fprintf(worGe,"\n");
    for(i=0 ; i < WG->qtdadePorTam[4]; i++){
        fprintf(worGe,"linha[4]:\n");
        fprintf(worGe,"%s |",WG->tam4[i]);
    }
    fprintf(worGe,"\n");
    for(i=0 ; i < WG->qtdadePorTam[5]; i++){
        fprintf(worGe,"linha[1]:\n");
        fprintf(worGe,"%s |",WG->tam5[i]);
    }

    printf("\nNumero de palavras inseridas no WG: %d\n", WG->totalWord);

    fclose(worGe);
}
